#!/usr/bin/env node
const { Command } = require("commander")
const mysql = require("mysql2")
const typeorm = new Command('typeorm')
const fs = require('fs')


typeorm
  .requiredOption('-h, --host <host>', '数据库地址, -h host, -h user@host, -h user:password@host')
  .option('-u, --user <user>', '数据库用户名')
  .option('-p, --password <password>', "数据库密码")
  .option('-db, --database <database>', "数据库名称")
  .requiredOption('-t, --table <table>', '表名, -t db.table')

typeorm.parse(process.agrv)

// console.log(typeorm.opts())
const { host, user, password, database, table } = typeorm.opts();

let typeormHost = '', // 服务器地址
typeormUser = '', // 用户名
typeormPassword = '', // 密码
typeormDatabase = '', // 数据库
typeormTable = ''; // 表名

const account = host.split(/[:@]/ig)
if (account.length === 3) {
  [typeormUser, typeormPassword, typeormHost] = account
} else if (account.length === 2) {
  [typeormUser, typeormHost] = account
} else {
  [typeormHost] = account
}
if (!typeormUser && typeof user === 'undefined') {
  console.error('数据库用户名 不能为空')
  process.exit(1);
}

typeormUser = typeof user !== 'undefined' ? user : typeormUser

if (!typeormPassword && typeof password === 'undefined') {
  console.error('数据库密码 不能为空')
  process.exit(1);
}

typeormPassword = typeof password !== 'undefined' ? password : typeormPassword

const dotIndex = table.indexOf('.')
if (dotIndex === table.length - 1) {
  console.error('请正确填写表名')
  process.exit(1);
}
if (dotIndex > 0 ) {
  [typeormDatabase, typeormTable] = table.split('.')
} else {
  typeormTable = table
}
if (!typeormDatabase && typeof database === 'undefined')  {
  console.error('请选择数据库')
  process.exit(1);
}
typeormDatabase = typeof database !== 'undefined' ? database : typeormDatabase

const config = {
  host: typeormHost,
  user: typeormUser,
  password: typeormPassword,
  database: typeormDatabase,
  table: typeormTable
}

async function createMysqlConnect (config) {
  const connection = mysql.createConnection({
    host: config.host,
    user: config.user,
    password: config.password,
    database: config.database
  })
  connection.query(`SHOW FULL FIELDS FROM ${config.table}`, (err, results) => {
    connection.end()
    if (err) {
      console.log(err)
      return
    }
    createTypeORMFile(results)
  })
  
}

function createTypeORMFile (results) {
  let table = config.table
  table = table[0].toUpperCase() + table.substr(1)
  table = table.replace(/[-_](.)/ig, (input, char) => {
    return char.toUpperCase()
  })
  let imports = ['Entity'], types = []
  let str = ''
  for (let key of results) {
    const { Field, Type, Collation, Null, Key, Default, Extra, Comment} = key
    const config  = {
      ...handleDataType(Type),
      name: Field,
      nullable: Null === 'NO',
      primary: Key === 'PRI',
      comment: Comment,
      default: Default,
      collation: Collation,
      extra: Extra
    }
    const {import: _import, column, type} = generatedBasic(config)
    imports.push(_import)
    types.push(type)
    str += column
  }
  const importsStr = 'import { ' + [...new Set(imports)].join(',') + ' } from "typeorm";'
  const typesStr = [...new Set(types)].join('\n')
  
  const retStr = `
${importsStr}
${typesStr}
@Entity()
export class ${table} {
  ${str}
}
`
fs.writeFileSync(__dirname+`/${table}.entity.ts`, retStr)
}

/**
 * 处理数据类型
 */
function handleDataType (type) {
  // 第一步分割
  const [dataType, ...other] = type.split(/\s+/ig)
  const retObj = {}
  for (let i = 0; i < other.length; i++) {
    retObj[other[i]] = true
  }
  if (dataType.indexOf('(') < 0) {
    return {
      ...retObj,
      type: dataType
    }
  } else {
    const regx = /(\w+)\((.+)\)/ig
    const [,_type, _value] = regx.exec(dataType)
    if (_type === 'enum') {
      return {
        ...retObj,
        type: _type,
        value: _value,
      }
    }
    const [, length, precision] = /^(\d+)(?:,(\d+))?$/ig.exec(_value)
    if (typeof precision !== 'undefined') {
      return {
        ...retObj,
        type: _type,
        length,
        precision
      }
    }
    return {
      ...retObj,
      type: _type,
      length
    }
  }
}
/**
 * 生成基本结构
 */
function generatedBasic (config) {
  const type = handleTypeToJsType(config.type)
  if (config.primary) {
    if (config.extra === 'auto_increment') {
      return {
        column: `
  // ${config.comment}
  @PrimaryGeneratedColumn()
  ${config.name}: ${type};
        `,
        import: 'PrimaryGeneratedColumn'
      }
    } else {
      return {
        column: `
  // ${config.comment}
  @PrimaryColumn()
  ${config.name}: ${type};
        `,
        import: 'PrimaryColumn'
      }
    }
  } else {
    delete config.extra
    if (type === 'enum') {
      const enums = config.value.split(',')
      const typeModel = config.name.toUpperCase() + 'TYPE'
      const arr = [
        `// ${config.comment}`,
        `@Column({`,
        `type: "enum",`,
        `enum: [${enums}],`,
        `nullable: ${config.nullable},`,
        `name: "${config.name}",`,
        `${config.length ? 'length: ' + config.length + ',': ''}`,
        `${config.precision ? 'precision: ' + config.precision + ',': ''}`,
        `${config.default === null ? '' : 'default: ' + config.default + ','}`,
        `${config.collation === null ? '' : 'collation: "' + config.collation + '",'}`,
        `${type === 'number' ? 'zerofill: ' + !!config.zerofill + ',': ''}`,
        `${type === 'number' ? 'unsigned: ' + !!config.unsigned + ',': ''}`,
        `})`,
        `${config.name}: ${typeModel};`
      ].filter((key) => key !== '').join('\n')
      return {
        import: 'Column',
        type: `export type ${typeModel} = ${enums.join('|')};`,
        column: arr
      }
    }
  }

  const arr = [
    `// ${config.comment}`,
    `@Column({`,
    `type: "${config.type}",`,
    `nullable: ${config.nullable},`,
    `name: "${config.name}",`,
    `${config.length ? 'length: ' + config.length + ',': ''}`,
    `${config.precision ? 'precision: ' + config.precision + ',': ''}`,
    `${config.default === null ? '' : 'default: ' + config.default + ','}`,
    `${config.collation === null ? '' : 'collation: "' + config.collation + '",'}`,
    `${type === 'number' ? 'zerofill: ' + !!config.zerofill + ',': ''}`,
    `${type === 'number' ? 'unsigned: ' + !!config.unsigned + ',': ''}`,
    `})`,
    `${config.name}: ${type};`
  ].filter((key) => key !== '').join('\n')
  return {
    import: 'Column',
    column: arr
  }
}

function handleTypeToJsType(type) {
  if (type === 'date') {
    return 'Date'
  }
  if (type === 'enum'){
    return 'enum'
  }
  const NUMERIC = [
    'tinyint',
    'smallint',
    'mediumint',
    'int',
    'bigint',
    'dec',
    'float',
    'double',
    'decimal',
    'numeric'
  ]
  return NUMERIC.includes(type) ? 'number' : 'string'
}
function generatedDate () {

}
function generatedEnum () {

}

createMysqlConnect(config)